/*
 * Class: CTLEngine
 * 
 * Description: Controller's main class. Links the interface package with the CEM package
 * 				and the dbManager
 * 
 * Version:
 * 1.0 - Nikolay Neshev - 06-11-2011
 * 		Initial implementation.
 * 1.1 - F-X Frenette - 09-12-2011
 * 		Modify interaction methods for interface
 * 		Modify comments for JAVADOC
 * 
 * Copyright GPP - Genuine People Personality inc
 * 
 */

package controller;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;


import calendarEventManager.*;
import calendarInterface2.CalendarInterface;
import calendarInterface2.OPError;
import dbManager.*;

public class CTLEngine {

	private static CalendarInterface s_oInterface;
	private static CEMCalendar s_oCalenderManager;
	private static DBMService s_oDataBaseManager;
	private static OPError s_oMessageDialog;

	//**************************************************************
	// Method: Main
	// Description: Entry point for the Calendar Application
	//**************************************************************
	/**
	 * 
	 */
	public static void main(String[] args) {
		// Initialising components
		s_oInterface 		= CalendarInterface.getInstance();
		s_oCalenderManager 	= CEMCalendar.getInstance();
		s_oDataBaseManager	= DBMService.getInstance();
		s_oMessageDialog	= new OPError();

		// Initialise and load the database in memory
		s_oDataBaseManager.initializeDataBase();
		loadDatabase();

		// Run the interface, which will call controller methods if needed
		s_oInterface.runInterface();
	} // main()

	//**************************************************************
	// Method: createAgenda
	// Description: Creates an agenda
	//**************************************************************
	/**
	 * @param p_sName
	 * 		Agenda's name
	 * @param p_nColour
	 * 		Agenda's colour
	 * @return boolean
	 * 		True if the agenda was created
	 */
	public static boolean createAgenda(String p_sName, int p_nColour){

		boolean bAgendaCreated = true;
		// Create object
		CEMAgenda oNewAgenda = new CEMAgenda(-1, p_sName, p_nColour);

		// Check if name is already used
		if(s_oDataBaseManager.nameAlreadyExist(oNewAgenda.getAgendaName())) {
			s_oMessageDialog.showErrorWindow("Agenda name already exists", "Creation error");
			bAgendaCreated = false;
		}
		else {
			// Update database
			if(s_oDataBaseManager.createAgenda(oNewAgenda)) {
				oNewAgenda.setAgendaId(s_oDataBaseManager.getAgendaId(oNewAgenda));		

				// Update memory
				s_oCalenderManager.addAgenda(oNewAgenda);
			}
			else {
				s_oMessageDialog.showErrorWindow("A problem occured with the database.\n" +
						"Restart the application and try again.", "Creation error");
				
				bAgendaCreated = false;
			}
		}
		
		return bAgendaCreated;

	} // createAgenda()

	//**************************************************************
	// Method: removeAgenda
	// Description: Removes an agenda
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		Agenda's Id
	 */
	public static void removeAgenda(int p_nAgendaId){
		List<CEMEvent> events = getAllEvents(p_nAgendaId);
		
		// Clear all events in agenda
		for(CEMEvent oEvent : events) {
			removeEvent(p_nAgendaId, oEvent.getEventId());
		}
		
		// Delete from agendas list
		if(s_oCalenderManager.deleteAgenda(p_nAgendaId) != CEMConstants.CEM_RETURN_CODE_OK) {
			s_oMessageDialog.showErrorWindow("Selected agenda doesn't exist (something went wrong)"
					, "Deletion error");
		}

		// Delete from the database
		else {
			if (!s_oDataBaseManager.deleteAgenda(p_nAgendaId)) {
				s_oMessageDialog.showErrorWindow("A problem occured with the database.\n" +
						"Restart the application and try again.", "Deletion error");
			}
		}

	} // removeAgenda()

	//**************************************************************
	// Method: getAllAgendas
	// Description: Returns all the agenda's from the application's
	//				memory
	//**************************************************************
	/**
	 * @return List<CEMAgenda>
	 * 		List of CEMAgendas or null if no agendas in memory
	 */
	public static List<CEMAgenda> getAllAgendas(){
		return s_oCalenderManager.getAgendaList();
	} // getAllAgendas()

	//**************************************************************
	// Method: getAgenda
	// Description: Returns an agenda from the application's memory
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		The agenda's Id
	 * @return CEMAgenda
	 * 		Returns the agenda or null if the agenda doesn't exist
	 * 		in memory
	 */
	public static CEMAgenda getAgenda(int p_nAgendaId){
		return s_oCalenderManager.getAgenda(p_nAgendaId);
	} // getAgenda()

	public static int getIdAgenda(String nameAgenda) {
		return s_oCalenderManager.getAgendaId(nameAgenda);
	}
	
	//**************************************************************
	// Method: updateAgenda
	// Description: Updates an existing agenda
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		Agenda's Id
	 * @param p_sNewName
	 * 		New Name
	 * @param p_nNewColour
	 * 		New Colour
	 * @return boolean
	 * 		True if the agenda was updated successfully
	 */
	public static boolean updateAgenda(int p_nAgendaId, String p_sNewName, int p_nNewColour){

		boolean bAgendaUpdated = true;
		
		CEMAgenda oAgenda = s_oCalenderManager.getAgenda(p_nAgendaId);
		if (oAgenda == null) {
			s_oMessageDialog.showErrorWindow(s_oMessageDialog.AGENDA_DONT_EXIST,s_oMessageDialog.UPDATE_FRAME);
			bAgendaUpdated = false;
		}
		else {
			oAgenda.setAgendaName(p_sNewName);
			oAgenda.setAgendaColour(p_nNewColour);

			if(!s_oDataBaseManager.updateAgenda(oAgenda)) {
				s_oMessageDialog.showErrorWindow(s_oMessageDialog.CANT_UPDATE_ERROR,s_oMessageDialog.CONNECTION_FRAME);
				bAgendaUpdated = false;
			}
		}
		
		return bAgendaUpdated;

	} // updateAgenda()

	//**************************************************************
	// Method: createEvent
	// Description: Creates an event
	//**************************************************************
	/**
	 * @param p_sName
	 * 		Event's name
	 * @param p_oStartTime
	 * 		Event's starting time
	 * @param p_oEndTime
	 * 		Event's ending time
	 * @param p_sDescription
	 * 		Event's Description
	 * @param p_sAgendaName
	 * 		Agenda's name
	 * @return boolean
	 * 		True if the event was created successfully
	 */
	public static boolean createEvent(	String p_sName, Timestamp p_oStartTime,
							Timestamp p_oEndTime, String p_sDescription, String p_sAgendaName) {
		
		boolean bEventCreated = true;
		
		int nAgendaId = getIdAgenda(p_sAgendaName);
		
		// Create object
		CEMEvent oNewEvent = new CEMEvent(-1, p_sName, p_oStartTime,p_oEndTime,p_sDescription,nAgendaId);

		// Check if event is in conflict with another one
		if(s_oDataBaseManager.checkConflictEvent(oNewEvent)) {
			s_oMessageDialog.showErrorWindow(s_oMessageDialog.ALREADY_AN_EVENT,s_oMessageDialog.UPDATE_FRAME);
			bEventCreated = false;
		}
		else {
			// Update database
			if(s_oDataBaseManager.createEvent(oNewEvent)) {
				oNewEvent.setEventId(s_oDataBaseManager.getEventId(oNewEvent));		

				// Update memory
				s_oCalenderManager.getAgenda(nAgendaId).addEvent(oNewEvent);
			}
			else {
				s_oMessageDialog.showErrorWindow(s_oMessageDialog.CANT_UPDATE_ERROR,s_oMessageDialog.CONNECTION_FRAME);
				bEventCreated = false;
			}
		}
		
		return bEventCreated;

	} // createEvent()

	//**************************************************************
	// Method: getEvent
	// Description: Returns an event from the application's memory
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		Id of the event's agenda
	 * @param p_nEventId
	 * 		Event's Id
	 * @return CEMEvent
	 * 		Returns the event
	 */
	public static CEMEvent getEvent(int p_nAgendaId, int p_nEventId) {
		return s_oCalenderManager.getAgenda(p_nAgendaId).getEvent(p_nEventId);
	} // getEvent()

	//**************************************************************
	// Method: updateEvent
	// Description: Updates an existing event
	//**************************************************************
	/**
	 * @param p_nEventId
	 * 		Updated event Id
	 * @param p_sNewName
	 * 		Updated name
	 * @param p_oNewStartTime
	 * 		Updated starting time
	 * @param p_oNewEndTime
	 * 		Updated ending time
	 * @param p_sNewDescription
	 * 		Updated description
	 * @param p_nAgendaId
	 * 		Updated agenda Id this event is part of
	 * @return boolean
	 * 		True if the event was updated successfully
	 */
	public static boolean updateEvent(	int p_nEventId, String p_sNewName, Timestamp p_oNewStartTime,
							Timestamp p_oNewEndTime, String p_sNewDescription, int p_nAgendaId) {

		boolean bEventUpdated = true;
		
		CEMEvent oEvent = s_oCalenderManager.getAgenda(p_nAgendaId).getEvent(p_nEventId);
		if (oEvent == null) {
			s_oMessageDialog.showErrorWindow(s_oMessageDialog.EVENT_DONT_EXIST,s_oMessageDialog.UPDATE_FRAME);
			bEventUpdated = false;
		}
		else {
			oEvent.setName(p_sNewName);
			oEvent.setDescription(p_sNewDescription);
			oEvent.setStartingTime(p_oNewStartTime);
			oEvent.setEndingTime(p_oNewEndTime);
			oEvent.setDescription(p_sNewDescription);

			if(!s_oDataBaseManager.updateEvent(oEvent)) {
				s_oMessageDialog.showErrorWindow(s_oMessageDialog.CANT_UPDATE_ERROR,s_oMessageDialog.CONNECTION_FRAME);
			}
		}
		
		return bEventUpdated;

	} // getEvent()

	//**************************************************************
	// Method: removeEvent
	// Description: Deletes an event
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		Agenda Id in which the event is
	 * @param p_nEventId
	 * 		Event's Id	
	 */
	public static void removeEvent(int p_nAgendaId, int p_nEventId){

		// Delete from Event list
		if(s_oCalenderManager.getAgenda(p_nAgendaId).deleteEvent(p_nEventId) != CEMConstants.CEM_RETURN_CODE_OK) {
			s_oMessageDialog.showErrorWindow(s_oMessageDialog.EVENT_DONT_EXIST,s_oMessageDialog.UPDATE_FRAME);
		}

		// Delete from the database
		else {
			if (!s_oDataBaseManager.deleteEvent(p_nEventId)) {
				s_oMessageDialog.showErrorWindow(s_oMessageDialog.CANT_UPDATE_ERROR,s_oMessageDialog.CONNECTION_FRAME);
			}
		}

	} // removeEvent()

	//**************************************************************
	// Method: getAllEvents
	// Description: Get all events
	//**************************************************************
	/**
	 * @return List<CEMEvent>
	 * 		The list of all events
	 */
	public static List<CEMEvent> getAllEvents(){
		List<CEMEvent> oEvents = new ArrayList<CEMEvent>();

		for (CEMAgenda oAgenda : s_oCalenderManager.getAgendaList()) {
			for(CEMEvent oEvent : oAgenda.getEventsList()) {
				oEvents.add(oEvent);
			}
		}

		return oEvents;		
	} // getAllEvents()	

	//**************************************************************
	// Method: getAllEvents
	// Description: Gets all events for a certain agenda
	//**************************************************************
	/**
	 * @param p_nAgendaId
	 * 		The id of the agenda's from which we want the events
	 * @return List<CEMEvent>
	 * 		The list of events for the agenda
	 */
	public static List<CEMEvent> getAllEvents(int p_nAgendaId){
		List<CEMEvent> oEvents = new ArrayList<CEMEvent>();

		for (CEMAgenda oAgenda : s_oCalenderManager.getAgendaList()) {
			if(oAgenda.getAgendaId() == p_nAgendaId) {
				for(CEMEvent oEvent : oAgenda.getEventsList()) {
					oEvents.add(oEvent);
				}
			}
		}

		return oEvents;	
	} // getAllEvents()

	//**************************************************************
	// Method: loadDatabase
	// Description: Loads the initial content of the database
	// 				into the memory
	//**************************************************************
	/**
	 * 
	 */
	public static void loadDatabase(){

		List<CEMAgenda> oAgendas = new ArrayList<CEMAgenda>();
		s_oDataBaseManager.selectAllTuple(oAgendas);
		
		for(CEMAgenda oAgenda : oAgendas) {
			List<CEMEvent> oEvents = new ArrayList<CEMEvent>();
			s_oDataBaseManager.selectAllTupleEvent(oEvents, oAgenda.getAgendaId());
			oAgenda.setEventsList(oEvents);
		}
		
		s_oCalenderManager.loadAgendas(oAgendas);

	} // loadDatabase()
	
	//**************************************************************
	// Method: exit
	// Description: Disconnect the database on exit
	//**************************************************************
	/**
	 * 
	 */
	public static void exit(){
		s_oDataBaseManager.disconnect();
	} // exit()


	
} // Class CTLEngine